package owg.util.awt;

import java.awt.Color;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.ParseException;

import javax.swing.JFormattedTextField;
import javax.swing.text.DefaultFormatter;
import javax.swing.text.DefaultFormatterFactory;

import owg.util.Calc;

public class StringFormattedEditor<T> extends TypeEditor<T> implements PropertyChangeListener {
	private static final long serialVersionUID = -6827401714155368963L;
	
	private JFormattedTextField field;
	private boolean ignoreEvents;
	private Color origcolor;
	
	@SuppressWarnings("unchecked")
	public StringFormattedEditor(T initialValue) {
		this((Class<T>) initialValue.getClass(), initialValue);
	}
	public StringFormattedEditor(Class<T> type, T initialValue) {
		super(type);
		if(initialValue == null)
		{
			System.err.println("Warning: Initial value of type "+type+" was set to null, attempting to create a default instance");
			try {
				initialValue = type.newInstance();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		ignoreEvents = false;
		field = new JFormattedTextField(initialValue);
		origcolor = field.getBackground();
		DefaultFormatter formatter = new DefaultFormatter();
		formatter.setValueClass(type);
		formatter.setOverwriteMode(false);
		field.setFormatterFactory(new DefaultFormatterFactory(formatter));
		//field.setFocusLostBehavior(JFormattedTextField.PERSIST);
		//The default focus lost behaviour is not triggered when the window loses focus.
		//This is a failure, so we need to do it ourselves.
		field.addFocusListener(new FocusListener() {
			@Override
			public void focusLost(FocusEvent e) {
				try {
					field.commitEdit();
				} catch (ParseException e1) {
					field.setValue(field.getValue());
				}
			}
			@Override
			public void focusGained(FocusEvent e) {
				// No
			}
		});
		field.setColumns(8);
		field.setValue(initialValue);
		add(field);
		field.addPropertyChangeListener("value", this);
	}
	
	@Override
	public T getValue()
	{
		return type.cast(field.getValue());
	}
	
	
	@Override
	public void setValue(T val)
	{
		ignoreEvents = true;
		int ppos = field.getCaretPosition();
		field.setValue(val);
		field.setText(String.valueOf(val));
		field.setCaretPosition((int)Calc.limit(ppos, 0, field.getText().length()+1));
		ignoreEvents = false;
	}
	
	@Override
	public void setToolTipTextToSubComponents(String text) {
		field.setToolTipText(text);
	}
	
	@Override
	public void setSubComponentsEnabled(boolean en) {
		field.setEnabled(en);
	}
	
	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		if(!ignoreEvents)
		{
			if(evt.getOldValue()==null?evt.getNewValue() != null : !evt.getOldValue().equals(evt.getNewValue()))
			{
				fireActionEvents();
				flash(Color.GREEN);
			}
		}
	}
	synchronized void color(Color color)
	{
		field.setBackground(color);
	}
	
	private void flash(Color color)
	{
		color(color);
		flashThread(new Runnable(){public void run(){color(origcolor);}}, 50);
	}
}
